Skip to content

Conversation

@dungbik
Copy link
Contributor

@dungbik dungbik commented Jul 16, 2025

📝 변경 내용


✅ 체크리스트

  • 코드가 정상적으로 동작함
  • 테스트 코드 통과함
  • 문서(README 등)를 최신화함
  • 코드 스타일 가이드 준수

💬 기타 참고 사항

Summary by CodeRabbit

  • 신규 기능

    • 토큰 버전 관리 기능이 추가되어, 사용자 토큰의 버전 정보를 저장 및 검증할 수 있습니다.
    • 토큰 버전 조회 및 저장을 위한 Redis 기반 저장소와 서비스가 도입되었습니다.
  • 개선 사항

    • JWT 토큰 생성 및 검증 과정에서 사용자 엔티티를 직접 활용하도록 개선되었습니다.
    • 인증 관련 데이터에 토큰 버전 정보가 포함되고, 토큰 버전 불일치 시 인증 예외가 발생하도록 강화되었습니다.
    • 회원 탈퇴 시 사용자 토큰 버전이 증가하고, 캐시에서 관련 정보가 삭제됩니다.
  • 버그 수정

    • 회원 탈퇴 시 연관된 토큰 버전 캐시가 삭제되어 보안성이 향상되었습니다.
  • 테스트

    • 변경된 토큰 생성 방식에 따라 인증 서비스 테스트 코드가 업데이트되었습니다.
    • 회원 탈퇴 시 토큰 버전 캐시 삭제 동작에 대한 테스트가 추가되었습니다.

@dungbik dungbik requested a review from stoneTiger0912 July 16, 2025 04:52
@dungbik dungbik self-assigned this Jul 16, 2025
@dungbik dungbik added the enhancement New feature or request label Jul 16, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 16, 2025

Caution

Review failed

The pull request is closed.

"""

Walkthrough

토큰 버전 관리 및 검증 기능이 추가되었습니다. User 엔티티와 JWT 처리 로직에 tokenVersion 필드가 도입되어, 로그아웃·탈퇴 등에서 토큰 무효화가 가능해졌습니다. Redis를 활용한 토큰 버전 캐싱 및 관련 서비스, 저장소, 설정이 함께 도입되었습니다.

Changes

파일/그룹 변경 요약
.../auth/constants/AuthRedisKey.java TOKEN_VERSION 상수 추가
.../auth/repository/TokenVersionRedisRepository.java 토큰 버전 Redis 저장소 신규 추가
.../auth/service/TokenVersionService.java 토큰 버전 조회 서비스 신규 추가
.../auth/service/AuthService.java JWT 생성 시 User 객체 전체 전달로 변경
.../common/config/RedisConfig.java tokenVersionRedisTemplate 빈 추가
.../common/security/dto/UserAuth.java tokenVersion 필드 record에 추가
.../common/security/jwt/JwtComponent.java User 기반 JWT 생성, 토큰 버전 검증, validateToken 메소드 추가
.../common/security/jwt/JwtConstants.java TOKEN_VERSION 상수 추가
.../user/entity/User.java tokenVersion 필드 및 증가 메소드 추가, softDelete → unregister 변경
.../user/repository/UserRepository.java findTokenVersionById 메소드 추가
.../user/service/UserService.java unregister에서 unregister() 호출 및 Redis 토큰 버전 삭제 추가
.../auth/service/AuthServiceTest.java JWT 생성 모킹 방식 User 객체 기반으로 변경
.../user/service/UserServiceTest.java TokenVersionRedisRepository 모킹 및 unregister 테스트에 삭제 검증 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant AuthService
    participant JwtComponent
    participant TokenVersionService
    participant TokenVersionRedisRepository
    participant UserRepository

    Client->>AuthService: login(로그인 요청)
    AuthService->>JwtComponent: generateTokenPair(User)
    JwtComponent->>User: User 정보에서 tokenVersion 추출
    JwtComponent-->>AuthService: TokenPair 반환

    Note over AuthService,JwtComponent: JWT에는 tokenVersion이 포함됨

    Client->>JwtComponent: extractUserAuthFromToken(JWT)
    JwtComponent->>TokenVersionService: findTokenVersion(userId)
    TokenVersionService->>TokenVersionRedisRepository: getTokenVersion(userId)
    alt Redis에 없음
        TokenVersionRedisRepository-->>TokenVersionService: 없음
        TokenVersionService->>UserRepository: findTokenVersionById(userId)
        UserRepository-->>TokenVersionService: tokenVersion 반환
        TokenVersionService->>TokenVersionRedisRepository: saveTokenVersion(userId, tokenVersion)
    end
    TokenVersionService-->>JwtComponent: tokenVersion 반환
    JwtComponent->>JwtComponent: validateToken(UserAuth)
    alt 토큰 버전 불일치
        JwtComponent-->>Client: SecurityException 발생
    else
        JwtComponent-->>Client: UserAuth 반환
    end
Loading

Possibly related PRs

  • Feat: [FN-60] 회원 탈퇴 #7: User의 탈퇴/삭제 로직에서 softDelete()를 INACTIVE로 상태 변경하는 것으로 확장하며, 이번 PR의 unregister() 및 토큰 버전 증가와 연관된 진화된 기능입니다.
  • Feat: [FN-43] 로그인 #6: AuthService.login 메서드 내부 JWT 생성 호출 방식을 User 객체 전달로 변경한 점에서 관련성이 있습니다.

Suggested reviewers

  • stoneTiger0912

Poem

🐰
토큰 버전 hop hop, 새로 추가됐지요!
로그아웃, 탈퇴에도 안전한 인증의 길,
Redis에 저장하고, User에 새겨
오래된 토큰은 이제 안녕!
FlipNote의 보안은 한층 더 튼튼해졌어요.

(🐇✨)
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d0d3f2 and b4a130e.

📒 Files selected for processing (2)
  • src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java (1 hunks)
  • src/main/java/project/flipnote/user/repository/UserRepository.java (2 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
src/main/java/project/flipnote/common/security/jwt/JwtComponent.java (1)

56-67: 토큰 생성 시 tokenVersion 클레임 누락

generateToken 메서드에서 tokenVersion을 JWT 클레임에 추가하지 않고 있습니다. 이로 인해 토큰 파싱 시 extractUserAuthFromClaims 메서드에서 NPE가 발생할 것입니다.

다음과 같이 수정해야 합니다:

 private String generateToken(User user, Date expiration) {
 	Date now = new Date();
 
 	return Jwts.builder()
 		.subject(user.getEmail())
 		.id(String.valueOf(user.getId()))
 		.claim(JwtConstants.ROLE, user.getRole().name())
+		.claim(JwtConstants.TOKEN_VERSION, user.getTokenVersion())
 		.issuedAt(now)
 		.expiration(expiration)
 		.signWith(secretKey, Jwts.SIG.HS256)
 		.compact();
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d254f8d and 03601d6.

📒 Files selected for processing (12)
  • src/main/java/project/flipnote/auth/constants/AuthRedisKey.java (1 hunks)
  • src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java (1 hunks)
  • src/main/java/project/flipnote/auth/service/AuthService.java (1 hunks)
  • src/main/java/project/flipnote/auth/service/TokenVersionService.java (1 hunks)
  • src/main/java/project/flipnote/common/config/RedisConfig.java (2 hunks)
  • src/main/java/project/flipnote/common/security/dto/UserAuth.java (1 hunks)
  • src/main/java/project/flipnote/common/security/jwt/JwtComponent.java (3 hunks)
  • src/main/java/project/flipnote/common/security/jwt/JwtConstants.java (1 hunks)
  • src/main/java/project/flipnote/user/entity/User.java (2 hunks)
  • src/main/java/project/flipnote/user/repository/UserRepository.java (2 hunks)
  • src/main/java/project/flipnote/user/service/UserService.java (3 hunks)
  • src/test/java/project/flipnote/auth/service/AuthServiceTest.java (4 hunks)
🔇 Additional comments (21)
src/main/java/project/flipnote/common/security/jwt/JwtConstants.java (1)

12-12: 상수 추가가 적절합니다.

JWT 클레임 키로 사용할 TOKEN_VERSION 상수가 올바르게 추가되었습니다. snake_case 네이밍 컨벤션을 따르고 있어 JWT 표준에 부합합니다.

src/main/java/project/flipnote/common/security/dto/UserAuth.java (1)

15-15: 토큰 버전 필드 추가가 적절합니다.

UserAuth 레코드에 tokenVersion 필드가 올바르게 추가되어 토큰 버전 관리 기능을 지원합니다. long 타입 사용과 네이밍 컨벤션이 적절합니다.

src/main/java/project/flipnote/auth/constants/AuthRedisKey.java (1)

11-13: Redis 키 상수 추가가 적절합니다.

토큰 버전 관리를 위한 TOKEN_VERSION 상수가 올바르게 추가되었습니다. 키 패턴 "auth:token:version:%d"과 TTL 3600초가 적절합니다. trailing comma 사용도 좋은 관례입니다.

src/main/java/project/flipnote/common/config/RedisConfig.java (1)

22-29: Redis 템플릿 설정이 적절합니다.

토큰 버전 관리를 위한 RedisTemplate<String, Long> 빈이 올바르게 구성되었습니다. 키 직렬화에 StringRedisSerializer, 값 직렬화에 GenericToStringSerializer<Long> 사용이 적절하며 기존 패턴과 일관성을 유지합니다.

src/test/java/project/flipnote/auth/service/AuthServiceTest.java (4)

181-181: JWT 생성 메서드 시그니처 변경에 맞게 테스트가 올바르게 업데이트되었습니다.

jwtComponent.generateTokenPair(foundUser) 호출이 새로운 API에 맞게 수정되어 User 객체를 전달하도록 변경되었습니다.


191-191: 검증 로직이 새로운 메서드 시그니처에 맞게 적절히 수정되었습니다.

verify(jwtComponent).generateTokenPair(any(User.class)) 호출이 변경된 API를 올바르게 검증합니다.


211-211: 실패 케이스 테스트의 검증 로직이 올바르게 업데이트되었습니다.

잘못된 이메일 케이스에서 generateTokenPair 메서드가 호출되지 않음을 검증하는 로직이 새로운 시그니처에 맞게 수정되었습니다.


234-234: 비밀번호 불일치 케이스의 검증 로직이 적절히 수정되었습니다.

잘못된 비밀번호 케이스에서도 generateTokenPair 메서드 호출이 없음을 검증하는 로직이 올바르게 업데이트되었습니다.

src/main/java/project/flipnote/user/service/UserService.java (2)

10-10: 토큰 버전 관리를 위한 Redis Repository 의존성 추가가 적절합니다.

JWT 토큰 무효화 기능 구현을 위해 필요한 의존성이 올바르게 추가되었습니다.

Also applies to: 28-28


60-61: 사용자 탈퇴 시 토큰 무효화 로직이 올바르게 구현되었습니다.

user.unregister() 호출로 토큰 버전을 증가시키고, Redis에서 토큰 버전을 삭제하는 순서가 적절합니다. 이를 통해 기존 JWT 토큰들이 무효화됩니다.

src/main/java/project/flipnote/auth/service/AuthService.java (1)

44-44: JWT 토큰 생성 방식 개선이 적절합니다.

토큰 버전 관리를 위해 User 객체 전체를 전달하는 방식으로 변경된 것이 합리적입니다. 이를 통해 tokenVersion을 포함한 모든 필요한 정보가 JWT 생성에 활용될 수 있습니다.

src/main/java/project/flipnote/user/repository/UserRepository.java (1)

22-23: 토큰 버전 조회를 위한 JPQL 쿼리가 적절합니다.

성능 최적화를 위해 필요한 tokenVersion 필드만 조회하는 것이 효율적입니다.

src/main/java/project/flipnote/user/entity/User.java (4)

58-59: 토큰 버전 필드 추가가 적절합니다.

JWT 토큰 무효화를 위한 tokenVersion 필드가 올바르게 정의되었습니다. nullable = false 설정도 적절합니다.


80-80: 토큰 버전 초기값 설정이 적절합니다.

새로운 사용자의 토큰 버전을 0으로 초기화하는 것이 합리적입니다.


83-89: 사용자 탈퇴 시 토큰 무효화 로직이 올바르게 구현되었습니다.

메서드명 변경(softDeleteunregister)과 토큰 버전 증가 로직이 적절하게 추가되었습니다. 이를 통해 탈퇴한 사용자의 기존 JWT 토큰들이 무효화됩니다.


91-93: 토큰 버전 증가 메서드가 간결하고 명확합니다.

토큰 버전을 1씩 증가시키는 로직이 명확하게 구현되었습니다.

src/main/java/project/flipnote/auth/service/TokenVersionService.java (1)

18-27: Redis 캐시와 DB 백업을 활용한 토큰 버전 조회 로직이 효율적으로 구현되었습니다.

캐시 우선 전략을 통해 성능을 최적화하고, cache miss 시 DB에서 조회 후 캐시에 저장하는 로직이 적절합니다. Optional 체이닝을 통한 구현도 깔끔합니다.

src/main/java/project/flipnote/auth/repository/TokenVersionRedisRepository.java (2)

18-23: LGTM!

토큰 버전을 TTL과 함께 Redis에 저장하는 로직이 올바르게 구현되었습니다.


32-36: LGTM!

토큰 버전 삭제 로직이 올바르게 구현되었습니다.

src/main/java/project/flipnote/common/security/jwt/JwtComponent.java (2)

69-75: 토큰 검증 로직이 적절히 구현됨

JWT 파싱 후 토큰 버전을 검증하는 로직이 올바르게 추가되었습니다.


91-98: LGTM!

토큰 버전 검증 로직이 명확하고 올바르게 구현되었습니다. 사용자 탈퇴 시 토큰 무효화가 제대로 작동할 것으로 보입니다.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/test/java/project/flipnote/user/service/UserServiceTest.java (1)

163-163: 토큰 버전 삭제 검증 로직이 추가됨

회원 탈퇴시 토큰 버전이 삭제되는지 검증하는 로직이 적절히 추가되었습니다. 현재 anyLong() 매처를 사용하고 있는데, 더 엄격한 테스트를 위해 실제 사용자 ID로 검증하는 것을 고려해볼 수 있습니다.

-			verify(tokenVersionRedisRepository, times(1)).deleteTokenVersion(anyLong());
+			verify(tokenVersionRedisRepository, times(1)).deleteTokenVersion(user.getId());
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 03601d6 and 7d0d3f2.

📒 Files selected for processing (1)
  • src/test/java/project/flipnote/user/service/UserServiceTest.java (3 hunks)
🔇 Additional comments (2)
src/test/java/project/flipnote/user/service/UserServiceTest.java (2)

20-20: 새로운 의존성 import가 적절히 추가됨

토큰 버전 관리 기능을 위한 TokenVersionRedisRepository import가 올바르게 추가되었습니다.


47-48: Mock 의존성이 올바르게 구성됨

TokenVersionRedisRepository에 대한 mock 필드가 적절한 어노테이션과 함께 추가되었습니다.

@dungbik dungbik merged commit 5a718da into develop Jul 16, 2025
2 of 3 checks passed
@dungbik dungbik deleted the feat/unregister-user branch July 16, 2025 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants